﻿using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LiteExpress.Utilities
{
    /// <summary>
    /// 对redis访问的封装，实例化对象尽量static
    /// </summary>
    public class RedisPackage
    {
        private string _server;
        public bool OnlineStatus = true;
        public DateTime? LastCheckTime = null;//上一次报错时间

        public RedisPackage(string server)
        {
            _server = server;
        }

        private ConnectionMultiplexer GetConnection()
        {
            var conn = ConnectionMultiplexer.Connect(_server);
            return conn;
        }

        public T GetClient<T>(Func<IDatabase, T> func)
        {
            return GetClient<T>(0, func);
        }

        public T GetClient<T>(int db, Func<IDatabase, T> func)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                return func(client);
            }
        }

        public bool GetTransaction(Action<ITransaction> func)
        {
            return GetTransaction(0, func);
        }

        public bool GetTransaction(int db, Action<ITransaction> func)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                var trans = client.CreateTransaction();
                func(trans);
                //tran.AddCondition(Condition.HashNotExists(custKey, "UniqueID"));
                //tran.HashSetAsync(custKey, "UniqueID", newId);
                bool success = trans.Execute();
                // ^^^ if true: it was applied; if false: it was rolled back
                return success;
            }
        }

        public bool Remove(string key, int db = 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                return client.KeyDelete(key);
            }
        }

        #region string
        public bool Set(string key, string value, int db = 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                return client.StringSet(key, value);
            }
        }

        public bool Add(string key, string value, TimeSpan expireIn, int db = 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                return client.StringSet(key, value, expireIn);
            }
        }

        public string Get(string key, int db = 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                return client.StringGet(key);
            }
        }
        #endregion

        #region set
        public IEnumerable<string> SMember(string key, int db = 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                var ret = client.SetMembers(key);

                return ret.Select(r => r.ToString());
            }
        }

        public bool SAdd(string key, string value, int db = 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                return client.SetAdd(key, value);
            }
        }

        public bool SRem(string key, string value, int db = 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                return client.SetRemove(key, value);
            }
        }
        #endregion

        #region sorted set
        public long ZRemRange(string key, double score1, double score2, int db = 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                return client.SortedSetRemoveRangeByScore(key, score1, score2);
            }
        }

        public bool ZAdd(string key, string value, double score, int db= 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                return client.SortedSetAdd(key, value, score);
            }
        }

        public IEnumerable<string> ZRange(string key, int start, int stop, int db = 0)
        {
            using (var conn = this.GetConnection())
            {
                var client = conn.GetDatabase(db);
                RedisValue[] ret;
                if (start > stop)
                {
                    ret = client.SortedSetRangeByRank(key, start, stop, Order.Descending);
                    //.GetRangeFromSortedSetDesc(key, start, stop);
                }
                else
                {
                    ret = client.SortedSetRangeByRank(key, start, stop, Order.Ascending);
                }
                return ret.Select(r => r.ToString());
            }
        }

        public IEnumerable<string> ZRangePage(string key, int page, int len)
        {
            int start = (page - 1) * len;
            int stop = page * len - 1;
            return ZRange(key, start, stop);
        }
        #endregion
    }
}
